package org.example.dingtalkintegrationservice.aspect;

import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.example.dingtalkintegrationservice.exception.GroovyExecutionException;
import org.example.dingtalkintegrationservice.pojo.log.ExecuteMethodLog;
import org.example.dingtalkintegrationservice.repository.ExecuteMethodLogRepository;
import org.springframework.stereotype.Component;


import java.lang.reflect.UndeclaredThrowableException;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

/**
 * @author pc
 */
@Slf4j
@Aspect
@Component
public class DingTalkIntegrationAspect {
    @Resource
    ExecuteMethodLogRepository executeMethodLogRepository;
    // 定义切点，拦截指定包下的所有方法
    @Pointcut("execution(* org.example.dingtalkintegrationservice.dingtalk..*(..))")
    public void dingTalkMethods() {}
//    // 在方法调用之前执行
//    @Before("dingTalkMethods()")
//    public void beforeMethod(JoinPoint joinPoint) {
////        log.info(MDC.get("requestId"));
//        System.out.println("Before executing method: " + joinPoint.getSignature());
//        ExecuteMethodLog executeMethodLog=new ExecuteMethodLog();
//        executeMethodLog.setMethod(joinPoint.getSignature().toString());
//
//        // 可以在这里添加统一的处理逻辑，如日志记录
//    }
//    // 在方法成功返回后执行
//    @AfterReturning(pointcut = "dingTalkMethods()", returning = "result")
//    public void afterReturningMethod(JoinPoint joinPoint, Object result) {
//        System.out.println("After executing method: " + joinPoint.getSignature() + ", Result: " + result);
//        // 可以在这里处理返回值
//    }
//    @AfterThrowing(pointcut = "dingTalkMethods()", throwing = "ex")
//    public void afterThrowingMethod(JoinPoint joinPoint, Throwable ex)  {
//        System.out.println("Exception in method: " + joinPoint.getSignature() + ", Exception: " + ex);
//        throw new RuntimeException("test");
//        // 可以在这里进行异常处理
//    }
    @Around("dingTalkMethods()")
    public Object logMethodExecution(ProceedingJoinPoint joinPoint) throws Throwable {
        ExecuteMethodLog executeMethodLog=new ExecuteMethodLog();
        executeMethodLog.setStartAt(LocalDateTime.now());
//        executeMethodLog.setRequestId(MDC.get("requestId"));
        long startTime = System.nanoTime();
        // 获取方法签名和输入参数
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        executeMethodLog.setMethod(methodSignature.toString());
        Object[] args = joinPoint.getArgs();
//        String[] parameterNames = methodSignature.getParameterNames();
//        Map<String, Object> inputMap = new HashMap<>();
        for (int i = 0; i < args.length; i++) {
            executeMethodLog.getInput().put(String.valueOf(i), args[i]);
        }
        // 记录方法输入
        Object result;
        try {
            // 执行目标方法
            result = joinPoint.proceed();
        } catch (Exception e) {
            if (e instanceof UndeclaredThrowableException){
                log.info("Undeclared！");
                Throwable realException=e.getCause();
                executeMethodLog.setErrorMsg(realException.getMessage());
                executeMethodLog.setErrorCause(Arrays.toString(realException.getStackTrace()));
                executeMethodLog.setErrorClass(realException.getClass().toString());
                executeMethodLog.setState("error");
                executeMethodLogRepository.save(executeMethodLog);
                log.error("Exception in method: " + methodSignature, realException);
                throw new RuntimeException(realException);
            }
            else{
            if(e instanceof GroovyExecutionException){
                executeMethodLog.setErrorLocation(((GroovyExecutionException) e).errorLocation);
                ((GroovyExecutionException) e).addErrorMethod(executeMethodLog.getMethod());
            }
            executeMethodLog.setErrorMsg(e.getMessage());
            executeMethodLog.setErrorCause(Arrays.toString(e.getStackTrace()));
            executeMethodLog.setErrorClass(e.getClass().toString());
            executeMethodLog.setState("error");
            executeMethodLogRepository.save(executeMethodLog);
            log.error("Exception in method: " + methodSignature, e);
            throw e;
            }
        }
        long endTime = System.nanoTime();
        long duration = TimeUnit.NANOSECONDS.toMillis(endTime - startTime);
        executeMethodLog.setEndAt(LocalDateTime.now());
        executeMethodLog.setDuration(duration);
        executeMethodLog.setOutput(result.toString());
        executeMethodLog.setState("success");
        // 记录方法输出和执行时间
        log.info("Method executed: " + methodSignature + ", Result: " + result + ", Duration: " + duration + " ms");
        executeMethodLogRepository.save(executeMethodLog);
        return result;
    }
}

